package com.genreate.util.apifoxUtil;

import cn.hutool.core.collection.IterUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.io.file.FileReader;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import org.apache.poi.xwpf.usermodel.*;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;

import java.io.FileOutputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class ApifoxUtil {
    public static void main(String[] args) {
        // 创建一个新的Word文档
        XWPFDocument doc = new XWPFDocument();

        List<List<ApiFoxData>> dataList = getJsonData();
        for (int i = 0; i < dataList.size(); i++) {
            List<ApiFoxData> apiFoxDataList = dataList.get(i);
            String parentName = apiFoxDataList.get(0).getParentName();
            // 添加段落（标题）
            addTitle(doc, StrUtil.format("{}.{}",i+1,parentName),2);
            for (int j = 0; j < apiFoxDataList.size(); j++) {
                ApiFoxData apiFoxData = apiFoxDataList.get(j);

                String xuhao = StrUtil.format("{}.{}", i + 1, j + 1);
                addTitle(doc, StrUtil.format("  {} {}",xuhao,apiFoxData.getMethodName()+"\n"),3);

                addParagraph(doc, "     "+apiFoxData.getMethodName() + "\n");

                createTabel(doc,apiFoxData);
            }
        }



        // 保存文档
        try (FileOutputStream out = new FileOutputStream("D:\\慧信顺\\交开投\\应急系统概要设计.docx")) {
            doc.write(out);
            System.out.println("Word文档生成成功！");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 添加标题
     * @param doc 文档对象
     * @param text 标题文本
     * @param level 标题级别（1-9）
     */
    private static void addTitle(XWPFDocument doc, String text, int level) {
        XWPFParagraph title = doc.createParagraph();
        title.setAlignment(ParagraphAlignment.LEFT); // 居中对齐
        title.setStyle("Heading" + level); // 设置标题样式

        XWPFRun run = title.createRun();
        run.setText(text);
        run.setFontSize(14 + (3 - level) * 2); // 根据级别调整字体大小
        run.setBold(true); // 标题加粗
    }

    /**
     * 添加普通正文段落
     * @param doc 文档对象
     * @param text 段落文本
     */
    private static void addParagraph(XWPFDocument doc, String text) {
        XWPFParagraph paragraph = doc.createParagraph();
        paragraph.setAlignment(ParagraphAlignment.LEFT); // 左对齐

        XWPFRun run = paragraph.createRun();
        run.setText(text);
        run.setFontSize(12); // 正文默认字体大小
        run.setFontFamily("宋体"); // 设置字体
    }

    /**
     * 获取解析的数据
     *
     * @return {@link List }<{@link List }<{@link ApiFoxData }>>
     */
    private static List<List<ApiFoxData>> getJsonData() {
        String pathFile = "D:\\ideaProjects\\GenerateUtil\\src\\main\\java\\com\\genreate\\util\\jtk\\test\\交开投.openapi.json";
        FileReader fileReader = new FileReader(pathFile);
        String result = fileReader.readString();
        JSONObject obj = JSONUtil.parseObj(result);

        //引用对象
        JSONObject refObj = obj.getJSONObject("components").getJSONObject("schemas");


        //父级目录
        JSONArray tags = obj.getJSONArray("tags");

        JSONObject paths = obj.getJSONObject("paths");

        List<ApiFoxData> apiFoxDataList = new ArrayList<>();

        int error = 0;
        for (String url : paths.keySet()) {
            ApiFoxData apiFoxData = new ApiFoxData();

            JSONObject jsonObject = paths.getJSONObject(url);
            //请求方式
            String requestMethod = jsonObject.keySet().iterator().next();

            //接口数据
            JSONObject urlData = jsonObject.getJSONObject(requestMethod);

            //父级目录名称
            String parentName = Convert.toStr(urlData.getJSONArray("tags").get(0));
            //接口名称
            String summary = urlData.getStr("summary");

            apiFoxData.setParentName(parentName);
            apiFoxData.setMethodName(summary);
            apiFoxData.setRequestDesc(summary);
            apiFoxData.setRequestMethod(requestMethod);
            apiFoxData.setRequestUrl(url);

            //请求数据列表
            List<RequestData> requestDataList = new ArrayList<>();
            JSONArray parameters = urlData.getJSONArray("parameters");
            if (IterUtil.isNotEmpty(parameters)) {
                List<JSONObject> parametersList = parameters.stream()
                        .map(e -> JSONUtil.parseObj(e))
                        .filter(e -> !"Authorization".equals(e.getStr("name")))
                        .collect(Collectors.toList());
                if (IterUtil.isNotEmpty(parametersList)) {
                    List<RequestData> parametersRequestDataList = parametersList.stream().map(e -> {
                        RequestData requestData = new RequestData();
                        requestData.setParamName(e.getStr("name"));
                        requestData.setParamType(JSONUtil.parseObj(e.getStr("schema")).getStr("type"));
                        requestData.setParamDesc(e.getStr("description"));
                        Boolean required = Convert.toBool(e.getBool("required"));
                        requestData.setRequired(required ? "是" : "否");
                        return requestData;
                    }).collect(Collectors.toList());
                    requestDataList.addAll(parametersRequestDataList);
                }
            }

            JSONObject requestBody = urlData.getJSONObject("requestBody");
            if (ObjectUtil.isNotEmpty(requestBody)) {
                //请求对象
                String requestBodyRef = requestBody.getJSONObject("content")
                        .getJSONObject("application/json")
                        .getJSONObject("schema").getStr("$ref");
                JSONObject properties = null;
                if (StrUtil.isNotBlank(requestBodyRef)) {
                    //请求对象名称
                    String requestBodyRefName = requestBodyRef.replaceAll("#/components/schemas/", "");
                    JSONObject refObject = refObj.getJSONObject(requestBodyRefName);
                    //所有字段
                    properties = refObject.getJSONObject("properties");
                } else {
                    properties = requestBody.getJSONObject("content")
                            .getJSONObject("application/json")
                            .getJSONObject("schema").getJSONObject("properties");
                }
                if (MapUtil.isNotEmpty(properties)) {
                    for (String fileName : properties.keySet()) {
                        JSONObject filedObj = properties.getJSONObject(fileName);
                        RequestData requestData = new RequestData();
                        requestData.setParamName(fileName);
                        requestData.setParamType(filedObj.getStr("type"));
                        requestData.setParamDesc(filedObj.getStr("description"));
                        Boolean required = Convert.toBool(filedObj.getBool("nullable"), false);
                        requestData.setRequired(required ? "是" : "否");
                        requestDataList.add(requestData);
                    }
                }
            }
            apiFoxData.setRequestDataList(requestDataList);

            /**
             * 返回数据列表
             */
            List<ResponseData> responseDataList = new ArrayList<>();
            //返回参数
            JSONObject responses = urlData.getJSONObject("responses");
            if (ObjectUtil.isNotEmpty(responses)) {
                //请求对象
                String responsesRef = null;
                try {
                    responsesRef = responses.getJSONObject("200")
                            .getJSONObject("content")
                            .getJSONObject("*/*")
                            .getJSONObject("schema").getStr("$ref");
                } catch (Exception e) {
                    System.out.println(StrUtil.format("错误数量：{}",error));
                    error++;
                    continue;
                }

                JSONObject properties = null;
                if (StrUtil.isNotBlank(responsesRef)) {
                    //请求对象名称
                    String requestBodyRefName = responsesRef.replaceAll("#/components/schemas/", "");
                    JSONObject refObject = refObj.getJSONObject(requestBodyRefName);
                    //所有字段
                    properties = refObject.getJSONObject("properties");
                } else {
                    properties = responses.getJSONObject("200")
                            .getJSONObject("content")
                            .getJSONObject("*/*")
                            .getJSONObject("schema").getJSONObject("properties");
                }

                if (MapUtil.isNotEmpty(properties)) {
                    for (String fileName : properties.keySet()) {
                        JSONObject filedObj = properties.getJSONObject(fileName);
                        ResponseData responseData = new ResponseData();
                        responseData.setParamName(fileName);
                        responseData.setParamType(filedObj.getStr("type"));
                        responseData.setParamDesc(filedObj.getStr("description"));
                        Boolean required = Convert.toBool(filedObj.getBool("nullable"), false);
                        responseData.setRequired(required ? "是" : "否");
                        responseDataList.add(responseData);
                    }
                    try {
                        Dict dict = getDict(properties, refObj);
                        apiFoxData.setResponseData(JSONUtil.toJsonPrettyStr(dict));
                    }catch (StackOverflowError e){
                        System.out.println(e);
                    }
                }
            }
            apiFoxData.setResponseDataList(responseDataList);
            apiFoxDataList.add(apiFoxData);
        }

        Map<String, List<ApiFoxData>> collect = apiFoxDataList.stream().collect(Collectors.groupingBy(ApiFoxData::getParentName));

        List<List<ApiFoxData>> res = new ArrayList<>();
        for (Object tag : tags) {
            String name = JSONUtil.parseObj(tag).getStr("name");
            List<ApiFoxData> now = collect.get(name);
            if(IterUtil.isNotEmpty(now)){
                res.add(now);
            }
        }

        return res;
    }

    public static Dict getDict(JSONObject properties, JSONObject allRef) {
        Dict dict = Dict.create();
        for (String fileName : properties.keySet()) {
            JSONObject filedObj = properties.getJSONObject(fileName);
            String ref = filedObj.getStr("$ref");
            if (StrUtil.isNotBlank(ref)) {
                String refName = ref.replaceAll("#/components/schemas/", "");
                JSONObject refObject = allRef.getJSONObject(refName);
                JSONObject propertiesChild = refObject.getJSONObject("properties");
                Dict childDict = getDict(propertiesChild, allRef);
                dict.set(fileName, childDict);
            }

            String type = filedObj.getStr("type");
            if (StrUtil.isNotBlank(type)) {
                switch (type.toLowerCase()) {
                    case "integer":
                        dict.set(fileName, 0);
                        break;
                    case "number":
                        dict.set(fileName, 0.0);
                        break;
                    case "string":
                        dict.set(fileName, "string");
                        break;
                    case "boolean":
                        dict.set(fileName, false);
                        break;
                    case "object":
                        dict.set(fileName, new Object());
                        break;
                    case "array":
                        dict.set(fileName, new ArrayList<>());
                        break;
                    default:
                        throw new RuntimeException("未找到类型");
                }
            }
        }

        return dict;
    }

    private static void createTabel(XWPFDocument doc, ApiFoxData apiFoxData) {
        //请求参数
        List<RequestData> requestDataList = apiFoxData.getRequestDataList();
        if(IterUtil.isEmpty(requestDataList)){
            requestDataList = ListUtil.toList(new RequestData());
        }
        //返回参数
        List<ResponseData> responseDataList = apiFoxData.getResponseDataList();
        if(IterUtil.isEmpty(responseDataList)){
            responseDataList = ListUtil.toList(new ResponseData());
        }

        //计算一共多少行
        int rowsTotal = 9 + requestDataList.size() + responseDataList.size();


        // 创建一个表格，共12行4列
        XWPFTable table = doc.createTable(rowsTotal, 4);

        // 设置表格宽度为页面宽度
        CTTblWidth width = table.getCTTbl().addNewTblPr().addNewTblW();
        width.setType(STTblWidth.DXA);
        width.setW(BigInteger.valueOf(9072));

        // 设置各列固定宽度
        setColumnWidth(table, 0, 2268); // 约25%宽度
        setColumnWidth(table, 1, 2268); // 约25%宽度
        setColumnWidth(table, 2, 2268); // 约25%宽度
        setColumnWidth(table, 3, 2268); // 约25%宽度

        // 设置表格整体内边距
        setTableCellMargins(table, 100, 100, 100, 100); // 上、右、下、左内边距

        // 第1行 第1和2列合并：接口方法名称 第3和4列合并：获取accessToken
        mergeCellsHorizontal(table, 0, 0, 1);
        mergeCellsHorizontal(table, 0, 2, 3);
        setCellText(table, 0, 0, "接口方法名称");
        setCellText(table, 0, 2, apiFoxData.getMethodName());

        // 第2行 第1和2列合并：请求方式， 第3和4列合并：POST
        mergeCellsHorizontal(table, 1, 0, 1);
        mergeCellsHorizontal(table, 1, 2, 3);
        setCellText(table, 1, 0, "请求方式");
        setCellText(table, 1, 2, apiFoxData.getRequestMethod());

        // 第3行 第1和2列合并：接口路径， 第3和4列合并：test/sdfsd
        mergeCellsHorizontal(table, 2, 0, 1);
        mergeCellsHorizontal(table, 2, 2, 3);
        setCellText(table, 2, 0, "接口路径");
        setCellText(table, 2, 2, apiFoxData.getRequestUrl());

        // 第4行 第1和2列合并：接口说明， 第3和4列合并：说明
        mergeCellsHorizontal(table, 3, 0, 1);
        mergeCellsHorizontal(table, 3, 2, 3);
        setCellText(table, 3, 0, "接口说明");
        setCellText(table, 3, 2, apiFoxData.getMethodName());

        // 第5行 将 1 2 3 4列合并为1列，为接口输入参数定义
        mergeCellsHorizontal(table, 4, 0, 3);
        setCellText(table, 4, 0, "接口输入参数定义");

        // 第6行 表头
        setCellText(table, 5, 0, "参数名称");
        setCellText(table, 5, 1, "参数类型");
        setCellText(table, 5, 2, "参数描述");
        setCellText(table, 5, 3, "是否必填");

        // 第7行 内容（使用较长文本测试换行）
        for (int i = 0; i < requestDataList.size(); i++) {
            int nowRow = 5 + i + 1;
            RequestData requestData = requestDataList.get(i);
            setCellText(table, nowRow, 0, getValue(requestData.getParamName()));
            setCellText(table, nowRow, 1, getValue(requestData.getParamType()));
            setCellText(table, nowRow, 2, getValue(requestData.getParamDesc()));
            setCellText(table, nowRow, 3, getValue(requestData.getRequired()));
        }

        // 第9行 将 1 2 3 4列合并为1列，为:接口返回值定义
        mergeCellsHorizontal(table, 5 + requestDataList.size() + 1, 0, 3);
        setCellText(table, 5 + requestDataList.size() + 1, 0, "接口返回值定义接口返回值定义接口返回值定义接口返回值定义接口返回值定义接口返回值定义接口返回值定义");

        // 第10行 表头
        int tabelRowRespone = 5 + requestDataList.size() + 2;
        setCellText(table, tabelRowRespone, 0, "返回值名称");
        setCellText(table, tabelRowRespone, 1, "类型");
        setCellText(table, tabelRowRespone, 2, "父级");
        setCellText(table, tabelRowRespone, 3, "字段描述");

        for (int i = 0; i < responseDataList.size(); i++) {
            ResponseData responseData = responseDataList.get(i);
            int nowRow = tabelRowRespone + i + 1;
            setCellText(table, nowRow, 0, getValue(responseData.getParamName()));
            setCellText(table, nowRow, 1, getValue(responseData.getParamType()));
            setCellText(table, nowRow, 2, "");
            setCellText(table, nowRow, 3, getValue(responseData.getParamDesc()));
        }


        // 第12行 将 1 2 3 4列合并为1列，为:xxx 高度设置高点
        int lastRowRespone = tabelRowRespone + responseDataList.size() + 1;
        mergeCellsHorizontal(table, lastRowRespone, 0, 3);
        setCellText(table, lastRowRespone, 0, getValue(apiFoxData.getResponseData()));
    }

    public static String getValue(Object o){
        return Convert.toStr(o,"");
    }

    /**
     * 合并单元格（水平方向）
     *
     * @param table    表格
     * @param row      行号
     * @param fromCell 起始列号
     * @param toCell   结束列号
     */
    private static void mergeCellsHorizontal(XWPFTable table, int row, int fromCell, int toCell) {
        for (int i = fromCell; i <= toCell; i++) {
            XWPFTableCell cell = table.getRow(row).getCell(i);
            if (i == fromCell) {
                // 第一个单元格设置为开始合并
                cell.getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.RESTART);
            } else {
                // 后续单元格设置为继续合并
                cell.getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.CONTINUE);
            }
        }
    }

    /**
     * 设置单元格文本并启用自动换行（兼容POI 4.1.2）
     *
     * @param table 表格
     * @param row   行号
     * @param col   列号
     * @param text  文本内容
     */
    private static void setCellText(XWPFTable table, int row, int col, String text) {
        XWPFTableCell cell = table.getRow(row).getCell(col);

        // 清空单元格原有内容
        while (cell.getParagraphs().size() > 0) {
            cell.removeParagraph(0);
        }

        // 创建新段落
        XWPFParagraph paragraph = cell.addParagraph();

        // 设置单元格自动换行（POI 4.1.2兼容写法）
        CTTc cttc = cell.getCTTc();
        CTTcPr tcPr = cttc.isSetTcPr() ? cttc.getTcPr() : cttc.addNewTcPr();

        // 直接创建textWrapping元素（POI 4.1.2不支持isSetTextWrapping()方法）
//        CTTextWrapping wrap = tcPr.addNewTextWrapping();
//        wrap.setVal(STTextWrapping.WRAP);

        // 设置段落属性
        CTPPr pPr = paragraph.getCTP().addNewPPr();
        pPr.addNewWordWrap().setVal(STOnOff.ON); // 允许单词换行

        // 设置段落间距
        CTSpacing spacing = pPr.addNewSpacing();
        spacing.setAfter(BigInteger.valueOf(60)); // 段落下方间距
        spacing.setBefore(BigInteger.valueOf(60)); // 段落上方间距

        // 创建文本运行
        XWPFRun run = paragraph.createRun();

        // 设置等宽字体，确保缩进对齐
        run.setFontFamily("Consolas"); // 或 "Courier New"
        run.setFontSize(10);

        // 处理文本中的换行符
        String[] lines = text.split("\n");
        for (int i = 0; i < lines.length; i++) {
            if (i > 0) {
                run.addBreak(); // 添加换行
            }
            run.setText(lines[i]);
        }
    }

    /**
     * 设置单元格文本并启用自动换行
     *
     * @param table 表格
     * @param row   行号
     * @param col   列号
     * @param text  文本内容
     */
    private static void setCellText222(XWPFTable table, int row, int col, String text) {
        XWPFTableCell cell = table.getRow(row).getCell(col);

        // 启用单元格自动换行
        CTTcPr tcPr = cell.getCTTc().addNewTcPr();

        // 创建段落
        XWPFParagraph paragraph = cell.getParagraphs().size() > 0 ? cell.getParagraphs().get(0) : cell.addParagraph();

        // 创建文本运行
        XWPFRun run = paragraph.createRun();
        run.setText(text);

        // 设置段落允许自动换行
        CTPPr pPr = paragraph.getCTP().addNewPPr();
        pPr.addNewWordWrap().setVal(STOnOff.ON);

        // 设置段落间距（增加垂直内边距）
        CTSpacing spacing = pPr.isSetSpacing() ? pPr.getSpacing() : pPr.addNewSpacing();
        spacing.setAfter(BigInteger.valueOf(60)); // 段落下方间距
        spacing.setBefore(BigInteger.valueOf(60)); // 段落上方间距

        pPr.addNewSpacing().setAfter(BigInteger.valueOf(60)); // 段落下方间距
    }

    /**
     * 设置列宽
     *
     * @param table  表格
     * @param column 列号
     * @param width  宽度（以twips为单位，1英寸=1440twips）
     */
    private static void setColumnWidth(XWPFTable table, int column, int width) {
        for (XWPFTableRow row : table.getRows()) {
            if (row.getTableCells().size() > column) {
                XWPFTableCell cell = row.getCell(column);
                CTTcPr tcPr = cell.getCTTc().addNewTcPr();
                CTTblWidth tcWidth = tcPr.addNewTcW();
                tcWidth.setType(STTblWidth.DXA);
                tcWidth.setW(BigInteger.valueOf(width));
            }
        }
    }

    /**
     * 设置单元格内边距（上下左右边距）
     *
     * @param table  表格
     * @param top    上内边距（twips）
     * @param right  右内边距（twips）
     * @param bottom 下内边距（twips）
     * @param left   左内边距（twips）
     */
    private static void setTableCellMargins(XWPFTable table, int top, int right, int bottom, int left) {
        CTTblPr tblPr = table.getCTTbl().getTblPr();
        if (tblPr == null) {
            tblPr = table.getCTTbl().addNewTblPr();
        }

        CTTblCellMar cellMar = tblPr.isSetTblCellMar() ? tblPr.getTblCellMar() : tblPr.addNewTblCellMar();

        // 上内边距
        if (top > 0) {
            CTTblWidth topBorder = cellMar.addNewTop();
//            topBorder.setW(BigInteger.ZERO);
            topBorder.setW(BigInteger.valueOf(top));
        }

        // 右内边距
        if (right > 0) {
            CTTblWidth rightBorder = cellMar.addNewRight();
//            rightBorder.setSz(BigInteger.ZERO);
            rightBorder.setW(BigInteger.valueOf(right));
        }

        // 下内边距
        if (bottom > 0) {
            CTTblWidth bottomBorder = cellMar.addNewBottom();
//            bottomBorder.setSz(BigInteger.ZERO);
            bottomBorder.setW(BigInteger.valueOf(bottom));
        }

        // 左内边距
        if (left > 0) {
            CTTblWidth leftBorder = cellMar.addNewLeft();
//            CTTblWidth.setSz(BigInteger.ZERO);
            leftBorder.setW(BigInteger.valueOf(left));
        }
    }
}